package com.iot.framework.mobile;


import com.alibaba.fastjson.JSONObject;
import com.iot.common.config.AliyunSmsTemplateCode;
import com.iot.common.constant.Constants;
import com.iot.common.constant.UserConstants;
import com.iot.common.core.domain.AjaxResult;
import com.iot.common.core.domain.entity.SysUser;
import com.iot.common.core.domain.model.LoginUser;
import com.iot.common.core.redis.RedisCache;
import com.iot.common.enums.UserStatus;
import com.iot.common.exception.ServiceException;
import com.iot.common.exception.user.*;
import com.iot.common.sms.AliSmsSender;
import com.iot.common.sms.SmsResult;
import com.iot.common.utils.*;
import com.iot.framework.manager.AsyncManager;
import com.iot.framework.manager.factory.AsyncFactory;
import com.iot.framework.web.service.PermissionService;
import com.iot.framework.web.service.SysLoginService;
import com.iot.framework.web.service.TokenService;
import com.iot.system.domain.MobileLoginParams;
import com.iot.system.service.ISysRoleService;
import com.iot.system.service.ISysUserService;
import com.google.code.kaptcha.Producer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 移动端登录服务接口
 */
@Component
public class MobileLoginService  {

    private static final Logger log = LoggerFactory.getLogger(MobileLoginService.class);

    @Resource
    private AuthenticationManager authenticationManager;

    @Autowired(required = false)
    private SysLoginService sysLoginService;

    @Autowired(required = false)
    private ISysRoleService sysRoleService;

    @Autowired(required = false)
    private ISysUserService sysUserService;

    @Autowired(required = false)
    private PermissionService permissionService;

    @Autowired(required = false)
    private AliSmsSender aliSmsSender;

    @Resource(name = "captchaProducerMath")
    private Producer captchaProducerMath;
    @Autowired
    private TokenService tokenService;

    /**
     * 注入redis服务
     */
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private AliyunSmsTemplateCode aliyunSmsTemplateCode;

    /**
     * 请求时间戳过期时间5分钟
     */
    private static final int REQUEST_TIME_OUT = 1000 * 60 * 5;

    public LoginUser login(MobileLoginParams mobileLoginParams) {
        log.debug("login and loginParams:{}", mobileLoginParams);

        if (Objects.isNull(mobileLoginParams)) {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor("未知用户", Constants.LOGIN_FAIL, MessageUtils.message("user.login.info.error")));
            throw new LoginInfoException();
        }
        String loginType = mobileLoginParams.getLoginType();
        if(StringUtils.isBlank(loginType)){
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(mobileLoginParams.getUsername(), Constants.LOGIN_FAIL, MessageUtils.message("user.login.info.error")));
            throw new LoginInfoException();
        }
        //登录方式0验证码登录，1用户名密码登录，2本机一键登录，3微信单点登录
        if(loginType.equals("0")){
            String verifyKey = Constants.LOGIN_CAPTCHA_CODE_KEY + mobileLoginParams.getPhoneNo();
            String captchaCode = redisCache.getCacheObject(verifyKey);
            if(captchaCode == null){
                throw new CaptchaExpireException();
            }else if(mobileLoginParams.getValidCode().equals(captchaCode)){
                LoginUser loginUser = sysLoginService.checkUserTypeByMobileNo(mobileLoginParams.getPhoneNo());
                return loginUser;
            }else{
                throw new CaptchaException();
            }
        }else if(loginType.equals("1")){
            String username = mobileLoginParams.getUsername();
            String password = mobileLoginParams.getPassword();
            return login(username, password);
        }
        return null;
    }

    /**
     * 登录
     */
    public LoginUser login(String username, String password)
    {
        // 用户名或密码为空 错误
        if (org.springframework.util.StringUtils.isEmpty(username) || org.springframework.util.StringUtils.isEmpty(password))
        {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("not.null")));
            throw new UserNotExistsException();
        }
        // 密码如果不在指定范围内 错误
        if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
                || password.length() > UserConstants.PASSWORD_MAX_LENGTH)
        {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
            throw new UserPasswordNotMatchException();
        }

        // 用户名不在指定范围内 错误
        if (username.length() < UserConstants.USERNAME_MIN_LENGTH
                || username.length() > UserConstants.USERNAME_MAX_LENGTH)
        {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
            throw new UserPasswordNotMatchException();
        }

        // 查询用户信息
        SysUser user = sysUserService.selectUserByUserName(username);

        /**if (user == null && maybeMobilePhoneNumber(username))
         {
         user = userService.selectUserByPhoneNumber(username);
         }

         if (user == null && maybeEmail(username))
         {
         user = userService.selectUserByEmail(username);
         }
         */

        if (user == null)
        {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.not.exists")));
            throw new UserNotExistsException();
        }

        if (user.isDelFlag())
        {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.delete")));
            throw new UserDeleteException();
        }

        if (UserStatus.DISABLE.getCode().equals(user.getStatus()))
        {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.blocked", user.getRemark())));
            throw new UserBlockedException();
        }

        if (!matches(user, password))
        {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.retry.limit.count")));
            throw new UserPasswordNotMatchException();
        }
        // 用户验证
        Authentication authentication = null;
        try
        {
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
            authentication = authenticationManager
                    .authenticate(new UsernamePasswordAuthenticationToken(username, password));
        }
        catch (Exception e)
        {
            if (e instanceof BadCredentialsException)
            {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
                throw new UserPasswordNotMatchException();
            }
            else
            {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
                throw new ServiceException(e.getMessage());
            }
        }
        AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        sysLoginService.recordLoginInfo(user.getUserId());
        return loginUser;
    }

    public boolean matches(SysUser user, String newPassword)
    {
        return SecurityUtils.matchesPassword(newPassword, user.getPassword());
    }

    /**
     * 发送注册验证码
     * @param mobileLoginParams
     * @return
     */
    public AjaxResult sendCode(MobileLoginParams mobileLoginParams) {
        if (Objects.isNull(mobileLoginParams)) {
            return AjaxResult.error("参数为空");
        }
        // 验证验证码
        if (StringUtils.isBlank(mobileLoginParams.getPhoneNo())) {
            return AjaxResult.error("发送手机号不能为空");
        }
        String validCodeType = "2";
        if (StringUtils.isNotBlank(mobileLoginParams.getValidCodeType())) {
            validCodeType = mobileLoginParams.getValidCodeType();
        }
        try{
            // 保存验证码信息
            String verifyKey = Constants.LOGIN_CAPTCHA_CODE_KEY + mobileLoginParams.getPhoneNo();
            String captchaCode = RandomUtil.genCaptchaNumber(6);
            redisCache.setCacheObject(verifyKey, captchaCode, 5, TimeUnit.MINUTES);
            JSONObject code = new JSONObject();
            code.put("code", captchaCode);
            SmsResult smsResult = aliSmsSender.send(mobileLoginParams.getPhoneNo(), aliSmsSender.getSignName(), aliyunSmsTemplateCode.getCaptchaCode(),
                    code.toJSONString(), null, null);
            if(!smsResult.isSuccess()){
                return AjaxResult.error("对不起手机号【"+ mobileLoginParams.getPhoneNo()+"】发送短信失败：失败原因:");
            }
        }catch (Exception e){
            throw new ServiceException(e.getMessage());
        }
        AjaxResult ajax = AjaxResult.success("验证码发送成功");
        return ajax;
    }

    /**
     * 手机号验证码注册用户
     * @param mobileLoginParams
     * @return
     */
    @Transactional(readOnly = false)
    public LoginUser registerUser(MobileLoginParams mobileLoginParams) {
        try{
            if (Objects.isNull(mobileLoginParams)) {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor("未知用户", Constants.LOGIN_FAIL, MessageUtils.message("user.login.info.error")));
                throw new LoginInfoException();
            }
            String phoneNo = mobileLoginParams.getPhoneNo();
            if (StringUtils.isBlank(phoneNo)) {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(mobileLoginParams.getUsername(), Constants.LOGIN_FAIL, MessageUtils.message("user.login.info.error")));
                throw new LoginInfoException();
            }
            String validCode = mobileLoginParams.getValidCode();
            if (StringUtils.isBlank(validCode)) {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(mobileLoginParams.getUsername(), Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
                throw new CaptchaException();
            }
            mobileLoginParams.setUsername(phoneNo);
            mobileLoginParams.setPassword(phoneNo);
            mobileLoginParams.setLoginType("1");
            return  this.login(mobileLoginParams);
        }catch (Exception e){
            throw new ServiceException(e.getMessage());
        }
    }

    /**
     * 设置注册用户角色部门岗位信息
     * @param registerUser
     * @return
     */
    private void setUserDefaultInfo(SysUser registerUser ){
        String registerRoleCode = DictUtils.getDictValue("sys_config","register_role_code","");
        if (StringUtils.isBlank(registerRoleCode)) {
            throw new ServiceException("请前往数据字典【sys_config】中维护注册用户角色编码【register_role_code】");
        }
        String registerDeptCode = DictUtils.getDictValue("sys_config","register_dept_code","");
        if (StringUtils.isBlank(registerDeptCode)) {
            throw new ServiceException("请前往数据字典【sys_config】中维护注册用户部门编码【register_dept_code】");
        }
        String registerPostCode = DictUtils.getDictValue("sys_config","register_post_code","");
        if (StringUtils.isBlank(registerPostCode)) {
            throw new ServiceException("请前往数据字典【sys_config】中维护注册用户岗位编码【register_post_code】");
        }

    }

}
